package ca.nfb.media.nfbPlayer
{
	import ca.nfb.media.nfbPlayer.ComModule;
	import ca.nfb.media.nfbPlayer.views.ControlBar;
	import ca.turbulent.media.Pyro
	import ca.turbulent.media.events.PyroEvent;
	import ca.turbulent.media.events.ErrorEvent;
	
	import flash.events.NetStatusEvent;
	import flash.events.AsyncErrorEvent;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.media.SoundTransform;
	import flash.net.SharedObject;
	import flash.utils.Timer;
	import flash.utils.*;
	import ca.turbulent.media.events.StatusUpdateEvent;
	
	public class NFBPyroBrew extends Pyro
	{
		
		public static const SWITCHING_FEED_START_EVENT		:String = "switchingFeedEvent";
		public static const SWITCHING_FEED_COMPLETED_EVENT	:String = "switchingFeedCompletedEvent";
		public static const STREAM_QUALITY_CHANGE			:String = "streamQualityChanged";
		public static const DETECTED_SPEED_2_LOW_FOR_QUALITY:String = "streamQualityTooHighEvent";
		
		public static const PLAYER_MODE_EMBEDDED			:String = "embedded";
		public static const PLAYER_MODE_FULL				:String = "full";
		
		public static const H_ALIGN_RIGHT					:String = "right";
		public static const H_ALIGN_LEFT					:String = "left";
		public static const H_ALIGN_CENTER					:String = "center";
		public static const V_ALIGN_TOP						:String = "top";
		public static const V_ALIGN_BOTTOM					:String = "bottom";
		public static const V_ALIGN_CENTER					:String = "center";
		
		public static const IMAGE_AUTOSIZE					:String = "autoSize";
		public static const IMAGE_NO_RESIZE					:String = "noResize";
		public static const IMAGE_RESIZE					:String = "resize"; 
		
		public static const FILE_TYPE_DV					:String = "dv";
		public static const FILE_TYPE_CC					:String = "cc";
		public static const FILE_TYPE_CCDV					:String = "ccdv";
		public static const FILE_TYPE_NORMAL				:String = "normal";
		
		public var extras							:Object = new Object();
		
		public var enableJSProgressEngine			:Boolean = false;
		public var hasOpaqueBackground				:Boolean = true;
		public var previewImageURL					:String = "";
		public var previewImageScaleMode			:String = IMAGE_RESIZE;
		
		public var usePreviewImage					:Boolean = false;
		public var useFullScreen					:Boolean = true;
		public var showWatermark					:Boolean = false;
		
		public var fileType							:String = FILE_TYPE_NORMAL;
		
		public var cookie							:SharedObject;
		public var streamQuality					:String;
		public var streamQualityCache				:String = "";
		public var isSwitchingFeed					:Boolean = false;
		public var isSwitchingSpeed					:Boolean = false;
		 
		public var changeConnectionWarned			:Boolean = false; 
		public var lowBandwidthWarned				:Boolean = false;
		 
		private var preSwitchFeedPaused				:Boolean = false;
		public var timeCache						:Number;
	
		
		private var progressTimer					:Timer;
		private var JSProgressTimer					:Timer;
		private var seekDelayTimer					:Timer = new Timer(100, 1);
		private var progressCallbacks				:Array = new Array();
		
		
		private var _defaultPreviewImageURL			:String = "";
		private var _JSProgressFrequency			:Number = 300;
		private var _playerMode						:String = PLAYER_MODE_FULL;
		private var _progressFrequency				:Number = 100;
		
		private var _checkCompletionTimer			:Timer	= new Timer(50, 0);
		public var bypassASYNCErrors				:Boolean= false;
		
		protected var completionTimeCache			:Array	= new Array();
		protected var lastTimeCached				:Number	= 0;
		protected var _firstRun						:Boolean = true;
		
		public function NFBPyroBrew(playerWidth:Number, playerHeight:Number):void
		{
			super(playerWidth, playerHeight);
			fetchCookie();
			this.bypassASYNCErrors = true;
		
			this.addEventListener(PyroEvent.BANDWIDTH_CHECKED, bandwidthChecked, false, 0, true);		
			
			
			if (this.hasEventListener(PyroEvent.STARTED))
				this.removeEventListener(PyroEvent.STARTED, started);
				
			this.addEventListener(PyroEvent.STARTED, started, false, 0, true);
	
			this.addEventListener(MouseEvent.CLICK, pyroClicked, false, 0, true);
			seekDelayTimer.addEventListener(TimerEvent.TIMER_COMPLETE, seekDelayed, false, 0, true);
			volumeCache = volume;
		}
		
		override protected function addedToStage(evt:Event):void
		{
			setDefaults();
			applyStageParameters();
			if (this.hasEventListener(Event.ADDED_TO_STAGE)) removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
			startInitTimer();
		}
		
		
		private function bandwidthChecked(evt:Event):void
		{
			if (cookie.data['streamQuality'] == null)
			{
				this.streamQuality = this.connectionSpeed;
				cookie.data['streamQuality'] = this.streamQuality;
			}
		}
		
		override protected function removedFromStage(evt:Event):void
		{
			stopProgressEngine();
			
			if (killOnRemoval)
			{
				if (!dying)
					kill(); 
			}
		}
		
		private function applyStageParameters():void
		{
			var p:Object = LoaderInfo(stage.loaderInfo).parameters;
			
			
			if (p.autoAdjustBufferTime && p.autoAdjustBufferTime != "" && (p.autoAdjustBufferTime == "true" || p.autoAdjustBufferTime == "false") && Boolean(p.autoAdjustBufferTime) != autoAdjustBufferTime)
				autoAdjustBufferTime = Boolean(p.autoAdjustBufferTime);
			
			if (p.autoAlign && p.autoAlign != "" && (p.autoAlign == "true" || p.autoAlign == "false") && Boolean(p.autoAlign) != autoAlign)
				autoAlign = Boolean(p.autoAlign);
				
				
			if (p.autoPlay && p.autoPlay != "" && (p.autoPlay == "true" || p.autoPlay == "false") && Boolean(p.autoPlay) != autoPlay)
				autoPlay = Boolean(p.autoPlay);	
			
			if (p.autoSize && p.autoSize != "" && (p.autoSize == "true" || p.autoSize == "false") && Boolean(p.autoSize) != autoSize)
				autoSize = Boolean(p.autoSize);		
			
			if (p.bufferTime && p.bufferTime != "" && Number(p.bufferTime) != bufferTime)
				bufferTime = Number(p.bufferTime);
			
			if (p.checkBandwidth && p.checkBandwidth != "" && (p.checkBandwidth == "true" || p.checkBandwidth == "false") && Boolean(p.checkBandwidth) != checkBandwidth)
				checkBandwidth = Boolean(p.checkBandwidth);	
				
			if (p.deblocking && p.deblocking != "" && Number(p.deblocking) != deblocking)
				deblocking = Number(p.deblocking);	
				
			if (p.enableJSProgressEngine && p.enableJSProgressEngine != "" && (p.enableJSProgressEngine == "true" || p.enableJSProgressEngine == "false") && Boolean(p.enableJSProgressEngine) != enableJSProgressEngine)
				enableJSProgressEngine = Boolean(p.enableJSProgressEngine);	
				
			if ((p.fullscreenMode && p.fullscreenMode != "" && p.fullscreenMode != fullscreenMode) && (p.fullscreenMode == Pyro.FS_MODE_SOFTWARE || p.fullscreenMode == Pyro.FS_MODE_HARDWARE)) 
				fullscreenMode = p.fullscreenMode;

			if (p.JSProgressFrequency && p.JSProgressFrequency != "" && Number(p.JSProgressFrequency) != _JSProgressFrequency)
				_JSProgressFrequency = Number(p.JSProgresFrequency);

			if ((p.maintainAspectRatio && p.maintainAspectRatio != "") && (p.maintainAspectRatio == "true" || p.maintainAspectRatio == "false") && (Boolean(p.maintainAspectRatio) != maintainAspectRatio))
			{
				maintainAspectRatio = Boolean(p.maintainAspectRatio);
			}
			
			if ((p.usePreviewImage && p.usePreviewImage != "") && (p.usePreviewImage == "true" || p.usePreviewImage == "false") && (p.usePreviewImage != usePreviewImage))
				usePreviewImage = p.usePreviewImage;
			
			/* if ((p.useRTMPExtension && p.useRTMPExtension != "") && (p.useRTMPExtension == "true" || p.useRTMPExtension == "false") && (p.useRTMPExtension != Pyro.RTMP_STREAM_NAME_HAS_EXTENSION))
				Pyro.RTMP_STREAM_NAME_HAS_EXTENSION = p.useRTMPExtension; */

			if ((p.previewImageURL && p.previewImageURL != "") && p.previewImageURL != previewImageURL) 	
				previewImageURL = p.previewImageURL;
				
			if (p.previewImageScaleMode && p.previewImageScaleMode != "" &&
				 (p.previewImageScaleMode == IMAGE_AUTOSIZE || p.previewImageScaleMode == IMAGE_NO_RESIZE || p.previewImageScaleMode == IMAGE_RESIZE) 
				 	&& p.previewImageScaleMode != previewImageScaleMode)
				previewImageScaleMode = p.previewImageScaleMode;
			
			if (p.progressFrequency && p.progressFrequency != "" && Number(p.progressFrequency) != _progressFrequency)
				_progressFrequency = Number(p.progresFrequency);
			
			if (p.scaleMode && p.scaleMode != "" && (p.scaleMode == Pyro.SCALE_MODE_WIDTH_BASED || p.scaleMode == Pyro.SCALE_MODE_HEIGHT_BASED || p.scaleMode == Pyro.SCALE_MODE_NO_SCALE) && p.scaleMode != scaleMode)
				scaleMode = p.scaleMode;	
			
			if (p.version && p.version != "")
			{
				if (p.version == Pyro.SERVER_TYPE_UNDER_FMS_3_5 || p.version == Pyro.SERVER_TYPE_LATEST || p.version==Pyro.SERVER_TYPE_NONE)
				{
					this.serverType = p.version;
				}
				else if (p.version == "FMS35")
				{
					this.serverType = Pyro.SERVER_TYPE_LATEST;
				}
				else if (p.version == "FMSUNDER35")
				{
					this.serverType = Pyro.SERVER_TYPE_UNDER_FMS_3_5;
				}
			}	
			
			if (p.serverType && p.serverType != "")
			{
				if (p.serverType == Pyro.SERVER_TYPE_UNDER_FMS_3_5 || p.serverType == Pyro.SERVER_TYPE_LATEST || p.serverType==Pyro.SERVER_TYPE_NONE)
				{
					this.serverType = p.serverType;
				}
				else if (p.serverType == "FMS35")
				{
					this.serverType = Pyro.SERVER_TYPE_LATEST;
				}
				else if (p.serverType == "FMSUNDER35")
				{
					this.serverType = Pyro.SERVER_TYPE_UNDER_FMS_3_5;
				}
			}	
			
			if (p.fileType != null && p.fileType != "")
			{
				fileType = p.fileType;		
			}
			
			if (p.scaleMode && p.scaleMode != "" && Boolean(p.scaleMode) != scaleMode)
			{
				if (p.scaleMode == "width")
				{
					scaleMode = Pyro.SCALE_MODE_WIDTH_BASED;
				}
				else if (p.scaleMode == "noScale")
				{
					scaleMode = Pyro.SCALE_MODE_NO_SCALE	
				}
				else
				{
					scaleMode = Pyro.SCALE_MODE_HEIGHT_BASED;
				}
			}
			
			if (p.showWatermark && p.showWatermark != "" && Boolean(p.showWatermark) != showWatermark)
				showWatermark = Boolean(p.showWatermark);
			
			if (p.smoothing && p.smoothing != "" && Boolean(p.smoothing) != smoothing)
				smoothing = Boolean(p.smoothing);
				
			if (p.useFullScreen && p.useFullScreen != "" && (p.useFullScreen == "true" || p.useFullScreen == false) && Boolean(p.useFullScreen) != useFullScreen)
				useFullScreen = Boolean(p.useFullScreen);
			
			if (p.volume && p.volume != "" && Number(p.volume) != volume)
				volume = p.volume;
				
			if (p.hAlignMode && p.hAlignMode != "" && (p.hAlignMode == Pyro.ALIGN_HORIZONTAL_LEFT || p.hAlignMode == Pyro.ALIGN_HORIZONTAL_RIGHT || p.hAlignMode == Pyro.ALIGN_HORIZONTAL_CENTER) && p.hAlignMode != hAlignMode)
				hAlignMode = p.hAlignMode;
				
			if (p.vAlignMode && p.vAlignMode != "" && (p.vAlignMode == Pyro.ALIGN_VERTICAL_BOTTOM || p.hAlignMode == Pyro.ALIGN_VERTICAL_TOP || p.hAlignMode == Pyro.ALIGN_VERTICAL_CENTER) && p.vAlignMode != vAlignMode)
				vAlignMode = p.vAlignMode;			 	
		
			if (ComModule.getInstance().core.requestedSizes.width != stage.stageWidth || ComModule.getInstance().core.requestedSizes.height != stage.stageHeight)
			{	
				if (ComModule.getInstance().core.showControls)
				{
					resize(ComModule.getInstance().core.requestedSizes.width, ComModule.getInstance().core.requestedSizes.height-44.7);	
				}
				else
				{
					resize(ComModule.getInstance().core.requestedSizes.width, ComModule.getInstance().core.requestedSizes.height);	
				}
			}
			
			
			if (ComModule.getInstance().packageFromURL)
			{
				try 
				{
					ComModule.getInstance().core.setCurrentState(NFBPlayer.DEFAULT_STATE);
					ComModule.getInstance().core.embeddedWelcomeView.visible = false;
				}
				catch(err:Error)
				{
					
				}
				
				
			}	
		}
		
		private function fetchCookie():void
		{
			cookie				= SharedObject.getLocal("NFBPlayer");
			
			if(cookie.data['volume'] == null)
				cookie.data['volume'] = volume;
			else
				volume = cookie.data['volume'];
			
			if (cookie.data['streamQuality'] == null || 
				(cookie.data['streamQuality'] != Pyro.CONNECTION_SPEED_HIGH && cookie.data['streamQuality'] != Pyro.CONNECTION_SPEED_MEDIUM && cookie.data['streamQuality'] != Pyro.CONNECTION_SPEED_LOW))	
			{
				if (!this.checkBandwidth)
					streamQuality = Pyro.CONNECTION_SPEED_MEDIUM;
			}
			else
			{
				streamQuality = cookie.data['streamQuality'];
			}	
						
		}
		
		private function pyroClicked(evt:MouseEvent):void
		{
			var core:NFBPlayer = ComModule.getInstance().core;		
			switch(core.currentState)
			{
				case NFBPlayer.SHARING_STATE:
				case NFBPlayer.END_PLAYLIST_STATE:
				case NFBPlayer.MORE_INFOS_STATE:
				case NFBPlayer.OPTIONS_STATE:
				break;
				
				case NFBPlayer.PREVIEW_IMAGE_STATE:
				core.previewImage.playMovie();
				break;
				
				default:
				if (core._movieID != "" || core.directURL != "" || ComModule.getInstance().latestFileURL != "")
					this.togglePause();
				break;
			}
		}
		
		public function setStreamQuality(qual:String):void
		{
			this.streamQualityCache = this.streamQuality;
			
			switch (qual)
			{
				case Pyro.CONNECTION_SPEED_HIGH:
				case Pyro.CONNECTION_SPEED_LOW:
				case Pyro.CONNECTION_SPEED_MEDIUM:
				this.streamQuality = qual;
				break;
			}
			
			cookie.data['streamQuality'] = this.streamQuality;
			cookie.flush();
				
			this.dispatchEvent(new Event(NFBPyroBrew.STREAM_QUALITY_CHANGE));
		
		}
		
		
		private function setDefaults():void
		{
			this.autoSize 				= false;
			this.maintainAspectRatio 	= true;
			this.serverType				= Pyro.SERVER_TYPE_UNDER_FMS_3_5; // Pyro.SERVER_TYPE_LATEST;
			
		//	this.useMetaData			= false;
			this.vAlignMode 			= Pyro.ALIGN_VERTICAL_CENTER;
			this.hAlignMode				= Pyro.ALIGN_HORIZONTAL_CENTER;
			this.autoPlay 				= true;
			this.scaleMode				= Pyro.SCALE_MODE_HEIGHT_BASED;
			this.smoothing 				= true;
			this.deblocking				= 0;
			this.checkBandwidth			= false;
			this.bufferTime				= 5;
			this.mouseEnabled 			= true;
			this.useHandCursor			= true;
			this.buttonMode 			= true;
			this.bufferingMode 			= Pyro.BUFFERING_MODE_SINGLE_TRESHOLD;
			this.autoAdjustBufferTime 	= false;
			this.checkBandwidth			= false;
			this.bufferEmptiedMaxOccurences = 2;
			this.autoAdjustBufferTime 	= false;
			
		}
		
		private function started(evt:Event):void
		{
			
			if (this.seekDelayTimer.running)
				this.seekDelayTimer.stop();
				
			if (this.isSwitchingFeed || this.isSwitchingSpeed)
			{
				if (this.streamType == Pyro.STREAM_TYPE_TRUE_STREAM)
				{	
					this.visible = false;
					// this.pause();
					startSeekDelay();						
				}
			}
		}
		
		private function startSeekDelay():void
		{
			this.seekDelayTimer.start();
		}
		
		private function seekDelayed(evt:TimerEvent):void
		{
			if (this.metadataReceived)
			{
				if (this.seekDelayTimer.running)
					this.seekDelayTimer.stop();
					
				// this.play();
				this.visible = true;
				this.seek(timeCache);
				isSwitchingFeed = false;
				isSwitchingSpeed = false;
				timeCache = 0;
				if (preSwitchFeedPaused)
					this.pause();
			}
			else
			{
				startSeekDelay();
			}		
		}
		
		public function overrideStreamQuality(qual:String):void
		{
			this.streamQuality = qual;
			cookie.data['streamQuality'] = this.streamQuality;	
			cookie.flush();
		}
		
		
		
		public function removeTabIndex():void
		{
			this.tabIndex = -1;
		}
		
		
		public function registerProgressCallback(callback:Object):void
		{
			progressCallbacks.push(callback); 
		}
		
		public function unregisterProgressCallback(callback:Object):void
		{
			
			for (var i:Number=0; i<progressCallbacks.length; ++i)
			{
				if (progressCallbacks[i]['name'] == callback['name'])
				{
					progressCallbacks.splice(i, 1);
					return;
				}	
			}
		}
		
		public function startProgressEngine():void
		{
			if (progressCallbacks.length > 0)
			{
				stopProgressEngine();
				
				if (progressTimer)
				{
					if (!progressTimer.hasEventListener(TimerEvent.TIMER))
						progressTimer.addEventListener(TimerEvent.TIMER, renderProgress, false, 0, true);
						
					if (!progressTimer.running)
						progressTimer.start();	
				}
				else
				{
					progressTimer = new Timer(this.progressFrequency, 0);
					progressTimer.addEventListener(TimerEvent.TIMER, renderProgress, false, 0, true);
					progressTimer.start();
				}
					
				if (enableJSProgressEngine)
				{	
					if (JSProgressTimer)
					{
						if (!JSProgressTimer.hasEventListener(TimerEvent.TIMER))
							JSProgressTimer.addEventListener(TimerEvent.TIMER, renderJSProgress, false, 0, true);
							
						if (!JSProgressTimer.running)
							JSProgressTimer.start();		
						
					}
					else
					{
						JSProgressTimer = new Timer(this.JSProgressFrequency, 0);						
						JSProgressTimer.addEventListener(TimerEvent.TIMER, renderJSProgress, false, 0, true);
						JSProgressTimer.start();	
					}
					
				}
			}	
		}
		
		public function stopProgressEngine():void
		{
			if (progressTimer)
			{
				if (progressTimer.running)
				{
					if (progressTimer.hasEventListener(TimerEvent.TIMER))
						progressTimer.removeEventListener(TimerEvent.TIMER, renderProgress);
						
					progressTimer.stop();
				}	
				progressTimer = null;		
			}
			
			if (JSProgressTimer)
			{
				if (JSProgressTimer.running)
				{
					if (JSProgressTimer.hasEventListener(TimerEvent.TIMER))
						JSProgressTimer.removeEventListener(TimerEvent.TIMER, renderJSProgress);	
					
					JSProgressTimer.stop();		
				}
					
				JSProgressTimer = null;
			}
		}
		
		public function switchFeed(newFeedURL:String):void
		{
			if (newFeedURL != this.urlDetails.rawURL)
			{
				this.dispatchEvent(new Event(NFBPyroBrew.SWITCHING_FEED_START_EVENT));
				isSwitchingFeed = true;
				timeCache = this.time;
				preSwitchFeedPaused = this.status == Pyro.STATUS_PAUSED;
				this.play(newFeedURL);
			}
			else
			{
				play();
			}	
		}
		
	
		private function renderProgress(evt:Event=null):void
		{
			var numCB:Number = progressCallbacks.length;
			
			if (numCB<=0)
				return;
				
			for (var i:Number=0; i<numCB; ++i)
				progressCallbacks[i].funct.call();
				
		}
		
		private function renderJSProgress(evt:Event=null):void
		{
			// call js progress callback
		}
		
		
		override public function toggleMute():void
		{
			_muted ? unmute() : mute();
			ComModule.getInstance().core.controlBar.mapVolumeSlider();
		}
		
		public function customRTMPPlay(streamer:String, file:String):void
		{
			
		}
		
	
		
		public function get JSProgressFrequency():Number { return _JSProgressFrequency; }
		public function get progressFrequency():Number { return _progressFrequency; }
		
		override public function set volume(vol:Number):void 
		{ 
			_volume = vol;
			if (connectionReady) { _nStream.soundTransform = new SoundTransform(vol, 0); }
		}
		
		override public function onTextData(textData:Object):void 
		{
			if (ComModule.getInstance().core.controlBar.subtitlesOn)
			{
				var textString:String = textData.text.toString();
				ComModule.getInstance().core.controlBar.subtitles.text = textString;
			}
		}
	
		
		public function pixelToTime(px:int):Number
		{
			return Math.floor(px / (ComModule.getInstance().core.controlBar.movableBars_mc.backgroundBar_mc.width) * duration);
		}
		
		public function timeToPixel(tmm):Number
		{
			return (tmm * ComModule.getInstance().core.controlBar.movableBars_mc.backgroundBar_mc.width) / duration ;
		}
		
		override protected function asyncErrorHandler(evt:AsyncErrorEvent):void 
		{
			if (!bypassASYNCErrors)
			{
				
				reset(); 
				dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, "ASYNC_ERROR", bubbleEvents, cancelableEvents));
			}
			 
		}
		
		override protected function onStreamStatus(evt:NetStatusEvent):void
		{
			
			
			switch (evt.info.code) 
            {
	        	case "NetStream.Pause.Notify":
		        	if (_status != Pyro.STATUS_PAUSED) 
		        	{ 	
		        		dispatchEvent(new PyroEvent(PyroEvent.PAUSED, bubbleEvents, cancelableEvents));
		        		setStatus(Pyro.STATUS_PAUSED);	
			       	}
            	break;
            	
                case "NetStream.Buffer.Empty":
	                if (autoAdjustBufferTime)
	                {
	                	if (_bufferEmptiedOccurences >= bufferEmptiedMaxOccurences)
	                	{
	                		switch (connectionSpeed)
	                		{
	                			case Pyro.CONNECTION_SPEED_HIGH:
		                			_connectionSpeed = Pyro.CONNECTION_SPEED_MEDIUM;
		                			adjustBufferTimes(_mediumSpeedBufferTable);
		                			_bufferEmptiedOccurences = 0;
		                			this.dispatchEvent(new PyroEvent(PyroEvent.BUFFER_TIME_ADJUSTED, bubbleEvents, cancelableEvents));	
	                			break;
	                			
	                			case Pyro.CONNECTION_SPEED_MEDIUM:
		                			_connectionSpeed = Pyro.CONNECTION_SPEED_LOW;
		                			adjustBufferTimes(_lowSpeedBufferTable);
		                			_bufferEmptiedOccurences = 0;	
		                			this.dispatchEvent(new PyroEvent(PyroEvent.BUFFER_TIME_ADJUSTED, bubbleEvents, cancelableEvents));
	                			break;
	                			
	                			case Pyro.CONNECTION_SPEED_LOW:
		                			_bufferEmptiedOccurences = 0;
		                			_lowSpeedBufferTable.singleTresholdBufferTime += _lowSpeedBufferTable.singleTresholdBufferTime*.1;
		                			this.dispatchEvent(new PyroEvent(PyroEvent.INSUFFICIENT_BANDWIDTH, bubbleEvents, cancelableEvents));
		                			ComModule.getInstance().core.tracker.sendBugReport(PyroEvent.INSUFFICIENT_BANDWIDTH);
	                			break;
	                		}
	                	}
	                	else
	                	{
	                		_bufferEmptiedOccurences++;
	                	}
	         	  	}
	                
	                if (this.bufferingMode == Pyro.BUFFERING_MODE_DUAL_TRESHOLD)
	                	this._nStream.bufferTime = this._dualStartBufferTime;
        	
					dispatchEvent(new PyroEvent(PyroEvent.BUFFER_EMPTY, bubbleEvents, cancelableEvents));
					checkCompletion();
               	break;
                
                case "NetStream.Buffer.Full":
               		if (_firstRun)
               		{
               			if (autoPlay)
               			{
               				this.setStatus(Pyro.STATUS_PLAYING);
               				_firstRun = false;
               			}	
               		}
               		dispatchEvent(new PyroEvent(PyroEvent.BUFFER_FULL, bubbleEvents, cancelableEvents));
               
	               	var currentBufferTable:BufferTimeTable;
	               	if (checkBandwidth && !bandwidthCheckDone) 
	               	{	
	               		
	               		var userBandwidth:Number;
	               		var connTime:Number = getTimer() - startTime;
	             		userBandwidth = (bufferLength * (streamDataRate) / (connTime/1000));
	             		
	             		// var buffer:Number = getBandwidth(_duration, this.streamDataRate, userBandwidth);
	               		if (userBandwidth <= 60)
						{
							_connectionSpeed = Pyro.CONNECTION_SPEED_LOW;
							currentBufferTable = _lowSpeedBufferTable;
							bufferEmptiedMaxOccurences = 3;
							if (this.streamQuality == Pyro.CONNECTION_SPEED_HIGH || this.streamQuality == Pyro.CONNECTION_SPEED_MEDIUM)
								this.dispatchEvent(new Event(NFBPyroBrew.DETECTED_SPEED_2_LOW_FOR_QUALITY, bubbleEvents, cancelableEvents));
									
						} 
						else
						{
							if (userBandwidth > 60 && userBandwidth <= 120)
							{
								bufferEmptiedMaxOccurences = 2;
								currentBufferTable = _mediumSpeedBufferTable;
								_connectionSpeed = Pyro.CONNECTION_SPEED_MEDIUM;	
								if (this.streamQuality == Pyro.CONNECTION_SPEED_HIGH)
									this.dispatchEvent(new Event(NFBPyroBrew.DETECTED_SPEED_2_LOW_FOR_QUALITY, bubbleEvents, cancelableEvents));
							}
							else if (userBandwidth > 120)
							{
								bufferEmptiedMaxOccurences = 1;
								currentBufferTable = _highSpeedBufferTable;
								_connectionSpeed = Pyro.CONNECTION_SPEED_HIGH;
							}
						}
						
						if (autoAdjustBufferTime)
							adjustBufferTimes(currentBufferTable);
						
						
	               		dispatchEvent(new PyroEvent(PyroEvent.BANDWIDTH_CHECKED, bubbleEvents, cancelableEvents));
	               		bandwidthCheckDone = true;
	               		
	               		if (this.bufferingMode == Pyro.BUFFERING_MODE_DUAL_TRESHOLD)
	               		 	_nStream.bufferTime = _dualStartBufferTime
	               	}

               	break;
                
                case "NetStream.Buffer.Flush":
	                flushed = true;
					dispatchEvent(new PyroEvent(PyroEvent.BUFFER_FLUSH, bubbleEvents, cancelableEvents));
				break;
				
                case "NetStream.Play.Complete":
	                
	                
	                if (status != Pyro.STATUS_COMPLETED)
	                {
	                	
	                	if (time >= (duration-.10))
	                	{	
	                		if (_checkCompletionTimer.running)
	   		             		_checkCompletionTimer.stop();
	                		
	                		
	                		 dispatchEvent(new PyroEvent(PyroEvent.COMPLETED, bubbleEvents, cancelableEvents));
		               		 _status = Pyro.STATUS_COMPLETED;
		                }
		                else
		                {
		           
		                	if (!_checkCompletionTimer.running)
		                	{
		                		ComModule.getInstance().core.tracker.trackErrorTimeLength("Completed Event received prematurely at"+this.formattedTime);
		                		_checkCompletionTimer.start();		
		               		} 
		                }
	                }
               	break;
                
                case "NetStream.Play.Reset":
                break;
                
                case "NetStream.Play.Start":
	               	if (!_firstRun)
					{
	               		if(autoPlay) { setStatus(Pyro.STATUS_PLAYING); }
	    			}	
	                
	                startTime = getTimer();
	                adjustSize();
	                
	                dispatchEvent(new PyroEvent(PyroEvent.STARTED, bubbleEvents, cancelableEvents));
                break;
                
                case "NetStream.Play.Stop":
                	
	                stopped = true;
	                adjustSize();
	                dispatchEvent(new PyroEvent(PyroEvent.STOPPED, bubbleEvents, cancelableEvents));
                break;
                              
                case "NetStream.Seek.Notify":
                	if (status != Pyro.STATUS_STOPPED) { dispatchEvent(new PyroEvent(PyroEvent.SEEKED, bubbleEvents, cancelableEvents)); }
                break;

               	case "NetStream.Play.StreamNotFound":
	               	setStatus(Pyro.STATUS_STOPPED);
	               	dispatchEvent(new ErrorEvent(ErrorEvent.FILE_NOT_FOUND_ERROR, evt.info.code, bubbleEvents, cancelableEvents));
               	break;
               	
               	case "NetStream.Unpause.Notify":
               	 dispatchEvent(new PyroEvent(PyroEvent.UNPAUSED, bubbleEvents, cancelableEvents));
                break;
               	
               	case "NetStream.Failed":
               	case "NetStream.Seek.Failed":		
               	case "NetStream.Play.Failed":
               	case "NetStream.Play.NoSupportedTrackFound":
         		case "NetStream.Play.FileStructureInvalid":
         		ComModule.getInstance().core.tracker.sendBugReport(evt.info.code);
         		dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, evt.info.code, bubbleEvents, cancelableEvents));
				
				this.stop();
				this.close();
				this.stopProgressEngine();
				break;	
					
				case "NetStream.Publish.BadName":
               	case "NetStream.Record.Failed":
				dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, evt.info.code, bubbleEvents, cancelableEvents));
				break;	
				
				case "NetStream.Play.InsufficientBW":
				
				dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, evt.info.code, bubbleEvents, cancelableEvents));
				dispatchEvent(new PyroEvent(PyroEvent.INSUFFICIENT_BANDWIDTH, bubbleEvents, cancelableEvents));	
				ComModule.getInstance().core.tracker.sendBugReport(evt.info.code);
				
				this.stop();
				this.stopProgressEngine();
				break;
					
				case "NetStream.Play.Switch":
               	break;
                	
               	case "NetStream.Publish.Idle":
                case "NetStream.Publish.Start":
                case "NetStream.Unpublish.Success":
                case "NetStream.Play.UnpublishNotify":
                case "NetStream.Play.UnpublishNotify":
               	case "NetStream.Record.Start":
               	case "NetStream.Record.NoAccess":
                case "NetStream.Record.Stop":
				break;
            }
            
            if(flushed && stopped)
            {
            	if (this.time > 0 && this.time < this.duration)
            	{
            		this.stopped = false;
            		this._checkCompletionTimer.start();
            	}
            	else
            	{
        			resetInternalState();
        			dispatchEvent(new PyroEvent(PyroEvent.COMPLETED, bubbleEvents, cancelableEvents));
            	}
			}
		}
		
		public function forceDispatchPending():void
		{
			this.dispatchEvent(new StatusUpdateEvent(StatusUpdateEvent.STATUS_UPDATE, Pyro.STATUS_PENDING));
		}
		
		private function checkCompletion(evt:TimerEvent=null):void
		{
			
			if (ComModule.getInstance().core.currentState != NFBPlayer.END_PLAYLIST_STATE)
			{
				if (this.time > 0)
				{
					if (time >= (duration-.10))
		        	{	
		        		
		        		this._checkCompletionTimer.stop();
		        		setStatus(Pyro.STATUS_COMPLETED);
		                dispatchEvent(new PyroEvent(PyroEvent.COMPLETED, bubbleEvents, cancelableEvents));
		            	completionTimeCache = new Array();
		            	return;
		            }
		            
		            if (lastTimeCached < this.time && lastTimeCached > 0)
		  			{
		  				lastTimeCached = this.time;
		  				completionTimeCache = new Array();
		            	return;
		     		}
		           	
		           	if (lastTimeCached > this.time && lastTimeCached > 0)
		           	{
		           		lastTimeCached = this.time;
		           		this._checkCompletionTimer.stop();
		           		completionTimeCache = new Array();
		           		return;	 
		            }
		           
		            if (this.status == Pyro.STATUS_PLAYING)
		            {
			           	if (completionTimeCache.length < 20 )
			           	{
			           		lastTimeCached = this.time;
			           		completionTimeCache.push(lastTimeCached);
			           	}
			           	else
			           	{
			           		this._checkCompletionTimer.stop();
			        		
			        		setStatus(Pyro.STATUS_COMPLETED);
		               	 	dispatchEvent(new PyroEvent(PyroEvent.COMPLETED, bubbleEvents, cancelableEvents));
			           	}
		            }
				}
				else
				{
					lastTimeCached = this.time;
		           	this._checkCompletionTimer.stop();
		           	completionTimeCache = new Array();
				}
			}	
		}
	}
}